package com.dasberg.guice;

import com.google.inject.Guice;
import com.google.inject.Injector;
import com.google.inject.Module;
import org.apache.log4j.Logger;

import java.util.ArrayList;
import java.util.List;

/**
 * Static injector for that holds all modules for Guice Dependency injection.
 * @author mischa
 */
public class StaticInjector {
    private static final Logger LOG = Logger.getLogger(StaticInjector.class);
    protected static Injector injector;
    private static List<Module> modules;

    /** Initialize the modules. */
    static {
        modules = new ArrayList<Module>();
    }

    /**
     * Inject the dependencies for the to be enrichted object.
     * @param toBeEnriched The object that needs to have its
     * dependencies injected.
     */
    public static void injectDependencies(Object toBeEnriched) {
        if (injector == null) {
            buildInjector();
        }
        injector.injectMembers(toBeEnriched);
    }

    /** Builds the Guice injector. */
    private static void buildInjector() {
        injector = Guice.createInjector(modules);
        LOG.debug("Guice injector build.");
    }

    /**
     * Registers a module and builds the Guice injector when the last
     * module is registered.
     * @param module The module.
     * @param build Indicates if this module is the last module we want
     * to inject.
     */
    public static void registerModule(Module module, boolean build) {
        if (!modules.contains(module)) {
            modules.add(module);
            if (build) {
                buildInjector();
            }
            LOG.debug("Registered module: " + module + ".");
        }
    }

    /**
     * Registers a module which is not the last module we want to register.
     * @param module The module.
     */
    public static void registerModule(Module module) {
        registerModule(module, false);
    }

    /**
     * Unregister a module which is not the last module we want to unregister.
     * @param module The module.
     * @param build Indicates if we need to build the injector.
     */
    public static void unregisterModule(Module module, boolean build) {
        if (modules.contains(module)) {
            modules.remove(module);
            if(build) {
                buildInjector();
            }
            LOG.debug("Unregistered module: " + module + ".");
        }
    }

    /**
     * Unregister a module which is not the last module we want to unregister.
     * @param module The module.
     */
    public static void unregisterModule(Module module) {
        unregisterModule(module, false);
    }

    /** Unregisters all modules. */
    public static void unregisterAllModules() {
        for (Module module : getModules()) {
            LOG.debug("Unregistered module: " + module + ".");
        }
        modules.clear();
        LOG.debug("Unregistered all modules");
        injector = null;
    }

    /**
     * Gets the modules.
     * @return modules The modules.
     */
    public static List<Module> getModules() {
        return modules;
    }

    /**
     * Gets the injector.
     * @return injector The injector.
     */
    protected static Injector getInjector() {
        return injector;
    }
}
